Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-258.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 1.683.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
4758 4748 2948 4747 2371    9 5888  714 3104 7904    8 1712 2465 8360 5419 1189 
  17   18   19   20   21   22   23   24   25 
5284 3369 4727 2722   62 6508 5544 4641 5680 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip", "nevada", "prof_nieve", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
        fecha_cnt       tmax       tmin     precip       nevada  prof_nieve
[1,]  0.009383255  0.6199373  0.6968202 -0.1597575 -0.020396010 -0.03428579
[2,] -0.733197864 -0.1632212 -0.1178331 -0.2512034 -0.007044088  0.01390443
       longitud    latitud    altitud
[1,] -0.3668900 -0.2430002 -0.2574485
[2,] -0.4705722 -0.2668660 -0.2143543

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
prof_nieve   longitud    latitud    altitud       tmax       tmin     nevada 
 0.9412848  0.9410938  0.9204962  0.9165983  0.9098795  0.9011940  0.8973951 
 fecha_cnt     precip 
 0.8966474  0.8384419 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.497   Mean   :200.2   Mean   :  98.88   Mean   : 16.25  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.00e+00   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :3.16e-05   Mean   :  0.3714   Mean   :39.66   Mean   : -3.4351  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :1.00e+00   Max.   :709.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.4  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:149.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.499   Mean   :200.3   Mean   :  98.96   Mean   : 16.22  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.00e+00   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :3.16e-05   Mean   :  0.1464   Mean   :39.66   Mean   : -3.4347  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :1.00e+00   Max.   :176.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 417.5  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 13.00   1st Qu.:-39.50   1st Qu.: 30.25  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 50.50  
 Mean   : 3.065   Mean   : 29.81   Mean   :-27.24   Mean   : 51.08  
 3rd Qu.: 3.000   3rd Qu.: 44.75   3rd Qu.:-17.00   3rd Qu.: 69.50  
 Max.   :12.000   Max.   : 96.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :177.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:225.2   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :283.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :344.3   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:456.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   :-53   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:146   1st Qu.:  50.00   1st Qu.:  3.00  
 Median : 6.000   Median :194   Median :  93.00   Median : 11.00  
 Mean   : 6.499   Mean   :199   Mean   :  94.92   Mean   : 16.95  
 3rd Qu.: 9.000   3rd Qu.:255   3rd Qu.: 141.00   3rd Qu.: 23.00  
 Max.   :12.000   Max.   :403   Max.   : 254.00   Max.   :422.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.99   1st Qu.: -4.8500  
 Median :0.00e+00   Median :  0.0000   Median :40.96   Median : -2.4831  
 Mean   :3.41e-05   Mean   :  0.1555   Mean   :40.55   Mean   : -2.4493  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.23   3rd Qu.:  0.4942  
 Max.   :1.00e+00   Max.   :176.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 251.0  
 Mean   : 409.5  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.503   Mean   :217.4   Mean   :150.6   Mean   :  6.924   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 13.00   1st Qu.:-39.50   1st Qu.: 30.25  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 50.50  
 Mean   : 3.065   Mean   : 29.81   Mean   :-27.24   Mean   : 51.08  
 3rd Qu.: 3.000   3rd Qu.: 44.75   3rd Qu.:-17.00   3rd Qu.: 69.50  
 Max.   :12.000   Max.   : 96.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :177.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:225.2   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :283.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :344.3   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:456.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 3.000   1st Qu.:147.0   1st Qu.:  47.00   1st Qu.:  3.00  
 Median : 6.000   Median :195.0   Median :  92.00   Median :  9.00  
 Mean   : 6.331   Mean   :200.5   Mean   :  94.09   Mean   : 12.56  
 3rd Qu.: 9.000   3rd Qu.:259.0   3rd Qu.: 142.00   3rd Qu.: 19.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :126.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.00e+00   Min.   :  0.0000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.00e+00   1st Qu.:  0.0000   1st Qu.:38.95   1st Qu.:-4.8500  
 Median :0.00e+00   Median :  0.0000   Median :40.87   Median :-2.4831  
 Mean   :3.78e-05   Mean   :  0.1634   Mean   :40.42   Mean   :-2.3990  
 3rd Qu.:0.00e+00   3rd Qu.:  0.0000   3rd Qu.:42.00   3rd Qu.: 0.4942  
 Max.   :1.00e+00   Max.   :176.0000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 264.0  
 Mean   : 431.2  
 3rd Qu.: 685.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.0   Min.   : 12.0   Min.   :0  
 1st Qu.: 6.000   1st Qu.:141.0   1st Qu.: 71.0   1st Qu.: 39.0   1st Qu.:0  
 Median : 9.000   Median :180.0   Median :102.0   Median : 52.0   Median :0  
 Mean   : 8.073   Mean   :184.7   Mean   :102.7   Mean   : 58.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:227.0   3rd Qu.:135.0   3rd Qu.: 69.0   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   :223.0   Max.   :422.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:41.22   1st Qu.: -6.0442   1st Qu.:  34.0  
 Median : 0.00000   Median :42.33   Median : -2.9056   Median :  98.0  
 Mean   : 0.08068   Mean   :41.75   Mean   : -2.9210   Mean   : 206.9  
 3rd Qu.: 0.00000   3rd Qu.:43.31   3rd Qu.:  0.5933   3rd Qu.: 333.0  
 Max.   :81.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.503   Mean   :217.4   Mean   :150.6   Mean   :  6.924   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 13.00   1st Qu.:-39.50   1st Qu.: 30.25  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 50.50  
 Mean   : 3.065   Mean   : 29.81   Mean   :-27.24   Mean   : 51.08  
 3rd Qu.: 3.000   3rd Qu.: 44.75   3rd Qu.:-17.00   3rd Qu.: 69.50  
 Max.   :12.000   Max.   : 96.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :177.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:225.2   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :283.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :344.3   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:456.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 3.000   Min.   :  8.0   Min.   :-110.0   Min.   : 0.000  
 1st Qu.: 7.000   1st Qu.:184.0   1st Qu.:  84.0   1st Qu.: 2.000  
 Median : 9.000   Median :247.0   Median : 132.0   Median : 7.000  
 Mean   : 8.768   Mean   :234.7   Mean   : 123.4   Mean   : 9.749  
 3rd Qu.:11.000   3rd Qu.:290.0   3rd Qu.: 169.0   3rd Qu.:15.000  
 Max.   :12.000   Max.   :403.0   Max.   : 254.0   Max.   :59.000  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.00e+00   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.00e+00   1st Qu.: 0.00000   1st Qu.:38.88   1st Qu.:-5.3456  
 Median :0.00e+00   Median : 0.00000   Median :40.82   Median :-3.1642  
 Mean   :4.49e-05   Mean   : 0.01897   Mean   :40.29   Mean   :-2.6320  
 3rd Qu.:0.00e+00   3rd Qu.: 0.00000   3rd Qu.:41.84   3rd Qu.: 0.3664  
 Max.   :1.00e+00   Max.   :59.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 261.0  
 Mean   : 381.8  
 3rd Qu.: 667.0  
 Max.   :2143.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.0   Min.   : 12.0   Min.   :0  
 1st Qu.: 6.000   1st Qu.:141.0   1st Qu.: 71.0   1st Qu.: 39.0   1st Qu.:0  
 Median : 9.000   Median :180.0   Median :102.0   Median : 52.0   Median :0  
 Mean   : 8.073   Mean   :184.7   Mean   :102.7   Mean   : 58.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:227.0   3rd Qu.:135.0   3rd Qu.: 69.0   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   :223.0   Max.   :422.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:41.22   1st Qu.: -6.0442   1st Qu.:  34.0  
 Median : 0.00000   Median :42.33   Median : -2.9056   Median :  98.0  
 Mean   : 0.08068   Mean   :41.75   Mean   : -2.9210   Mean   : 206.9  
 3rd Qu.: 0.00000   3rd Qu.:43.31   3rd Qu.:  0.5933   3rd Qu.: 333.0  
 Max.   :81.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 3.000   1st Qu.: 27.00   1st Qu.: -35.00   1st Qu.: 21.00  
 Median : 6.000   Median : 67.00   Median :   1.00   Median : 32.00  
 Mean   : 6.528   Mean   : 72.61   Mean   :   5.04   Mean   : 36.37  
 3rd Qu.:10.000   3rd Qu.:117.00   3rd Qu.:  45.00   3rd Qu.: 48.00  
 Max.   :12.000   Max.   :218.00   Max.   : 128.00   Max.   :126.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :  0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:  0.00   1st Qu.:41.77   1st Qu.: 0.7317   1st Qu.:1894  
 Median :0   Median :  0.00   Median :42.47   Median : 0.9844   Median :2230  
 Mean   :0   Mean   :  3.87   Mean   :42.09   Mean   : 0.1334   Mean   :2169  
 3rd Qu.:0   3rd Qu.:  0.00   3rd Qu.:42.64   3rd Qu.: 1.5242   3rd Qu.:2400  
 Max.   :0   Max.   :176.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.0   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:133.0   1st Qu.: 31.0   1st Qu.: 5.00  
 Median :3.000   Median :164.0   Median : 62.0   Median :12.00  
 Mean   :2.982   Mean   :163.1   Mean   : 60.5   Mean   :14.67  
 3rd Qu.:4.000   3rd Qu.:194.0   3rd Qu.: 90.0   3rd Qu.:22.00  
 Max.   :7.000   Max.   :300.0   Max.   :180.0   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.00e+00   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.00e+00   1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.8458  
 Median :0.00e+00   Median : 0.00000   Median :40.95   Median :-2.3438  
 Mean   :3.07e-05   Mean   : 0.09109   Mean   :40.46   Mean   :-2.2646  
 3rd Qu.:0.00e+00   3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5356  
 Max.   :1.00e+00   Max.   :75.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 251.0  
 Mean   : 372.1  
 3rd Qu.: 656.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.000   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.503   Mean   :217.4   Mean   :150.6   Mean   :  6.924   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03086   Mean   :28.36   Mean   :-16.05   Mean   : 518.7  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 13.00   1st Qu.:-39.50   1st Qu.: 30.25  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 50.50  
 Mean   : 3.065   Mean   : 29.81   Mean   :-27.24   Mean   : 51.08  
 3rd Qu.: 3.000   3rd Qu.: 44.75   3rd Qu.:-17.00   3rd Qu.: 69.50  
 Max.   :12.000   Max.   : 96.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :177.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:225.2   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :283.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :344.3   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:456.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip     
 Min.   : 7.00   Min.   :  8.0   Min.   :-110.0   Min.   : 0.00  
 1st Qu.:11.00   1st Qu.:115.0   1st Qu.:  26.0   1st Qu.: 4.00  
 Median :11.00   Median :150.0   Median :  55.0   Median :11.00  
 Mean   :11.31   Mean   :150.1   Mean   :  57.7   Mean   :13.52  
 3rd Qu.:12.00   3rd Qu.:181.0   3rd Qu.:  89.0   3rd Qu.:21.00  
 Max.   :12.00   Max.   :293.0   Max.   : 189.0   Max.   :59.00  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.0000000   1st Qu.: 0.00000   1st Qu.:38.37   1st Qu.:-4.6800  
 Median :0.0000000   Median : 0.00000   Median :40.82   Median :-2.1381  
 Mean   :0.0001496   Mean   : 0.05633   Mean   :40.16   Mean   :-2.1204  
 3rd Qu.:0.0000000   3rd Qu.: 0.00000   3rd Qu.:41.67   3rd Qu.: 0.5706  
 Max.   :1.0000000   Max.   :59.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 263.0  
 Mean   : 381.4  
 3rd Qu.: 667.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 3.000   Min.   :135.0   Min.   :  8.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:241.0   1st Qu.:124.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 8.000   Median :274.0   Median :153.0   Median : 5.000   Median :0  
 Mean   : 7.676   Mean   :270.9   Mean   :151.5   Mean   : 8.131   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:302.0   3rd Qu.:181.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :51.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud    
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:38.88   1st Qu.:-5.5975   1st Qu.:  44  
 Median : 0.00000   Median :40.80   Median :-3.5556   Median : 251  
 Mean   : 0.00295   Mean   :40.35   Mean   :-2.8513   Mean   : 382  
 3rd Qu.: 0.00000   3rd Qu.:42.01   3rd Qu.: 0.3056   3rd Qu.: 667  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :2143  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.0   Min.   : 12.0   Min.   :0  
 1st Qu.: 6.000   1st Qu.:141.0   1st Qu.: 71.0   1st Qu.: 39.0   1st Qu.:0  
 Median : 9.000   Median :180.0   Median :102.0   Median : 52.0   Median :0  
 Mean   : 8.073   Mean   :184.7   Mean   :102.7   Mean   : 58.1   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:227.0   3rd Qu.:135.0   3rd Qu.: 69.0   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   :223.0   Max.   :422.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:41.22   1st Qu.: -6.0442   1st Qu.:  34.0  
 Median : 0.00000   Median :42.33   Median : -2.9056   Median :  98.0  
 Mean   : 0.08068   Mean   :41.75   Mean   : -2.9210   Mean   : 206.9  
 3rd Qu.: 0.00000   3rd Qu.:43.31   3rd Qu.:  0.5933   3rd Qu.: 333.0  
 Max.   :81.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 3.000   1st Qu.: 27.00   1st Qu.: -35.00   1st Qu.: 21.00  
 Median : 6.000   Median : 67.00   Median :   1.00   Median : 32.00  
 Mean   : 6.528   Mean   : 72.61   Mean   :   5.04   Mean   : 36.37  
 3rd Qu.:10.000   3rd Qu.:117.00   3rd Qu.:  45.00   3rd Qu.: 48.00  
 Max.   :12.000   Max.   :218.00   Max.   : 128.00   Max.   :126.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :  0.00   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:  0.00   1st Qu.:41.77   1st Qu.: 0.7317   1st Qu.:1894  
 Median :0   Median :  0.00   Median :42.47   Median : 0.9844   Median :2230  
 Mean   :0   Mean   :  3.87   Mean   :42.09   Mean   : 0.1334   Mean   :2169  
 3rd Qu.:0   3rd Qu.:  0.00   3rd Qu.:42.64   3rd Qu.: 1.5242   3rd Qu.:2400  
 Max.   :0   Max.   :176.00   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin            precip     
 Min.   : 1.000   Min.   : 69.00   Min.   :-15.00   Min.   : 3.00  
 1st Qu.: 2.000   1st Qu.: 76.00   1st Qu.: -5.00   1st Qu.: 9.00  
 Median : 2.000   Median : 91.00   Median : -1.00   Median :14.00  
 Mean   : 5.222   Mean   : 94.44   Mean   : 10.89   Mean   :12.89  
 3rd Qu.:12.000   3rd Qu.: 97.00   3rd Qu.: 30.00   3rd Qu.:15.00  
 Max.   :12.000   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada        prof_nieve        longitud        latitud      
 Min.   :2.000   Min.   : 0.000   Min.   :40.48   Min.   :-3.450  
 1st Qu.:2.000   1st Qu.: 0.000   1st Qu.:40.48   1st Qu.:-3.450  
 Median :2.000   Median : 1.000   Median :41.67   Median :-1.033  
 Mean   :2.778   Mean   : 3.111   Mean   :41.14   Mean   :-2.107  
 3rd Qu.:3.000   3rd Qu.: 5.000   3rd Qu.:41.67   3rd Qu.:-1.033  
 Max.   :6.000   Max.   :13.000   Max.   :41.67   Max.   :-1.033  
    altitud     
 Min.   :263.0  
 1st Qu.:263.0  
 Median :263.0  
 Mean   :416.4  
 3rd Qu.:608.1  
 Max.   :608.1  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin           precip     
 Min.   :1.000   Min.   : -4.0   Min.   :-89.0   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:133.0   1st Qu.: 31.0   1st Qu.: 5.00  
 Median :3.000   Median :164.0   Median : 62.0   Median :12.00  
 Mean   :2.982   Mean   :163.1   Mean   : 60.5   Mean   :14.67  
 3rd Qu.:4.000   3rd Qu.:194.0   3rd Qu.: 90.0   3rd Qu.:22.00  
 Max.   :7.000   Max.   :300.0   Max.   :180.0   Max.   :80.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.00e+00   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.00e+00   1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.8458  
 Median :0.00e+00   Median : 0.00000   Median :40.95   Median :-2.3438  
 Mean   :3.07e-05   Mean   : 0.09109   Mean   :40.46   Mean   :-2.2646  
 3rd Qu.:0.00e+00   3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5356  
 Max.   :1.00e+00   Max.   :75.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  44.0  
 Median : 251.0  
 Mean   : 372.1  
 3rd Qu.: 656.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94.0   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :129.0   Median : 51.00   Median :  3.00   Median :0  
 Mean   : 6.585   Mean   :138.4   Mean   : 60.83   Mean   : 10.29   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183.0   3rd Qu.: 98.00   3rd Qu.: 13.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253.0   Max.   :159.00   Max.   :114.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1766   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 13.00   1st Qu.:-39.50   1st Qu.: 30.25  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 50.50  
 Mean   : 3.065   Mean   : 29.81   Mean   :-27.24   Mean   : 51.08  
 3rd Qu.: 3.000   3rd Qu.: 44.75   3rd Qu.:-17.00   3rd Qu.: 69.50  
 Max.   :12.000   Max.   : 96.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :177.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:225.2   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :283.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :344.3   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:456.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax          tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87   Min.   : 64.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 3.000   1st Qu.:212   1st Qu.:150.0   1st Qu.: 0.000   1st Qu.:0  
 Median : 6.000   Median :233   Median :168.0   Median : 1.000   Median :0  
 Mean   : 6.486   Mean   :234   Mean   :169.4   Mean   : 6.219   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:259   3rd Qu.:196.0   3rd Qu.: 7.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356   Max.   :244.0   Max.   :94.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003521   Mean   :28.38   Mean   :-15.95   Mean   :130.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAyNTgKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQKKiBEaW1lbnNpb25lcyBkZWwgbWFwYTogNSw1CiogSXRlcmFjaW9uZXM6IDEwMDAwCiogUGFyw6FtZXRyb3MgYWRpY2lvbmFsZXM6IAoKYGBge3J9CnNvdXJjZSgiLi4vLi4vbGliL3NvbS11dGlscy5SIikKc291cmNlKCIuLi8uLi9saWIvbWFwcy11dGlscy5SIikKYGBgCgojIENhcmdhIGRlbCBtb2RlbG8gZGVzZGUgZGlzY28KCmBgYHtyfQptcHIuc2V0X2Jhc2VfcGF0aF9hbmFseXNpcygpCm1vZGVsIDwtIG1wci5sb2FkX21vZGVsKCJzb20tMjU4LnJkcy54eiIpCnN1bW1hcnkobW9kZWwpCmBgYAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNoYW5nZXMiKQpgYGAKCiMgQ2FyZ2EgZGVsIGRhdGFzZXQgZGUgZW50cmFkYQoKYGBge3J9CmRmIDwtIG1wci5sb2FkX2RhdGEoImRhdG9zX21lcy5jc3YueHoiKQpgYGAKCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCiMgQ2FyZ2EgZGUgbG9zIG1hcGFzCgpgYGB7cn0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKc3BhaW4gPC0gc3Vic2V0KHdvcmxkLCBhZG1pbiA9PSAiU3BhaW4iKQpgYGAKCiMgTWFwYSBkZSBkZW5zaWRhZAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNvdW50Iiwgc2hhcGUgPSAic3RyYWlnaHQiLCBwYWxldHRlLm5hbWUgPSBtcHIuZGVncmFkZS5ibGV1KQpgYGAKCk7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2VsZGE6CgpgYGB7cn0KbmIgPC0gdGFibGUobW9kZWwkdW5pdC5jbGFzc2lmKQpwcmludChuYikKYGBgCkNvbXByb2JhY2nDs24gZGUgbm9kb3MgdmFjw61vczoKCmBgYHtyfQpkaW1fbW9kZWwgPC0gNSo1OwpsZW5fbmIgPSBsZW5ndGgobmIpOwplbXB0eV9ub2RlcyA8LSBkaW1fbW9kZWwgIT0gbGVuX25iOwppZiAoZW1wdHlfbm9kZXMpIHsKICBwcmludChwYXN0ZSgiW1dhcm5pbmddIEV4aXN0ZW4gbm9kb3MgdmFjw61vczogIiwgbGVuX25iLCAiLyIsIGRpbV9tb2RlbCkpCn0KYGBgCgojIE1hcGEgZGUgZGlzdGFuY2lhIGVudHJlIHZlY2lub3MKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJkaXN0Lm5laWdoYm91cnMiLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyBJbmZsdWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQptb2RlbF9jb2xuYW1lcyA9IGMoImZlY2hhX2NudCIsICJ0bWF4IiwgInRtaW4iLCAicHJlY2lwIiwgIm5ldmFkYSIsICJwcm9mX25pZXZlIiwgImxvbmdpdHVkIiwgImxhdGl0dWQiLCAiYWx0aXR1ZCIpCm1vZGVsX25jb2wgPSBsZW5ndGgobW9kZWxfY29sbmFtZXMpCmBgYAoKIyMgTWFwYSBkZSB2YXJpYWJsZXMuCgpgYGB7cn0KcGxvdChtb2RlbCwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMjIE1hcGEgZGUgY2Fsb3IgcG9yIHZhcmlhYmxlCgpgYGB7cn0KcGFyKG1mcm93PWMoMyw0KSkKZm9yIChqIGluIDE6bW9kZWxfbmNvbCkgewogIHBsb3QobW9kZWwsIHR5cGU9InByb3BlcnR5IiwgcHJvcGVydHk9Z2V0Q29kZXMobW9kZWwsMSlbLGpdLAogICAgcGFsZXR0ZS5uYW1lPW1wci5jb29sQmx1ZUhvdFJlZCwKICAgIG1haW49bW9kZWxfY29sbmFtZXNbal0sCiAgICBjZXg9MC41LCBzaGFwZSA9ICJzdHJhaWdodCIpCn0KYGBgCgojIyBDb3JyZWxhY2nDs24gcGFyYSBjYWRhIGNvbHVtbmEgZGVsIHZlY3RvciBkZSBub2RvcwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBjb3IgPC0gYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksIDIsIG1wci53ZWlnaHRlZC5jb3JyZWxhdGlvbiwgdz1uYiwgc29tPW1vZGVsKQogIHByaW50KGNvcikKfQpgYGAKClJlcHJlc2VudGFjacOzbiBkZSBjYWRhIHZhcmlhYmxlIGVuIHVuIG1hcGEgZGUgZmFjdG9yZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBhcihtZnJvdz1jKDEsMSkpCiAgcGxvdChjb3JbMSxdLCBjb3JbMixdLCB4bGltPWMoLTEsMSksIHlsaW09YygtMSwxKSwgdHlwZT0ibiIpCiAgbGluZXMoYygtMSwxKSxjKDAsMCkpCiAgbGluZXMoYygwLDApLGMoLTEsMSkpCiAgdGV4dChjb3JbMSxdLCBjb3JbMixdLCBsYWJlbHM9bW9kZWxfY29sbmFtZXMsIGNleD0wLjc1KQogIHN5bWJvbHMoMCwwLGNpcmNsZXM9MSxpbmNoZXM9RixhZGQ9VCkKfQpgYGAKCkltcG9ydGFuY2lhIGRlIGNhZGEgdmFyaWFibGUgLSB2YXJpYW56YSBwb25kZXJhZGEgcG9yIGVsIHRhbWHDsW8gZGUgbGEgY2VsZGE6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHNpZ21hMiA8LSBzcXJ0KGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLDIsZnVuY3Rpb24oeCxlZmZlY3RpZikKICAgICB7bTwtc3VtKGVmZmVjdGlmKih4LXdlaWdodGVkLm1lYW4oeCxlZmZlY3RpZikpXjIpLyhzdW0oZWZmZWN0aWYpLTEpfSwKICAgICBlZmZlY3RpZj1uYikpCiAgcHJpbnQoc29ydChzaWdtYTIsZGVjcmVhc2luZz1UKSkKfQpgYGAKCiMgQ2x1c3RlcmluZwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBoYWMgPC0gbXByLmhhYyhtb2RlbCwgbmIpCn0KYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAzIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MykKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTMpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTQpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz00KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA1IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NSkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTUpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA2IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NikKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTYpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgOCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTgpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz04KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMTAgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0xMCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTEwKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQogIGRmLmNsdXN0ZXIwOSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTkpCiAgZGYuY2x1c3RlcjEwIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MTApCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDkgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjEwIDwtIHNlbGVjdChkZi5jbHVzdGVyMTAsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0sIGRpbShkZi5jbHVzdGVyMDkpWzFdLCBkaW0oZGYuY2x1c3RlcjEwKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiLCAiY2x1c3RlcjA5IiwgImNsdXN0ZXIxMCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMTApCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMTApCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQogIGRmLmNsdXN0ZXIwOS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA5KQogIGRmLmNsdXN0ZXIxMC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjEwKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA5Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjEwLmdyb3VwZWQpCmBgYAo=